diff options
Diffstat (limited to 'app/[lng]/evcp')
| -rw-r--r-- | app/[lng]/evcp/(evcp)/b-rfq/page.tsx | 3 | ||||
| -rw-r--r-- | app/[lng]/evcp/(evcp)/evaluation-check-list/page.tsx | 18 | ||||
| -rw-r--r-- | app/[lng]/evcp/(evcp)/evaluation-target-list/page.tsx | 65 | ||||
| -rw-r--r-- | app/[lng]/evcp/(evcp)/evaluation/page.tsx | 19 | ||||
| -rw-r--r-- | app/[lng]/evcp/(evcp)/system/layout.tsx | 11 | ||||
| -rw-r--r-- | app/[lng]/evcp/(evcp)/system/password-policy/page.tsx | 63 |
6 files changed, 98 insertions, 81 deletions
diff --git a/app/[lng]/evcp/(evcp)/b-rfq/page.tsx b/app/[lng]/evcp/(evcp)/b-rfq/page.tsx index 213e9127..a66d7b58 100644 --- a/app/[lng]/evcp/(evcp)/b-rfq/page.tsx +++ b/app/[lng]/evcp/(evcp)/b-rfq/page.tsx @@ -46,6 +46,8 @@ export default async function PQReviewPage(props: PQReviewPageProps) { }) ]) + console.log(search, "견적") + return ( <Shell className="gap-4"> <div className="flex items-center justify-between space-y-2"> @@ -60,7 +62,6 @@ export default async function PQReviewPage(props: PQReviewPageProps) { {/* Items처럼 직접 테이블 렌더링 */} <React.Suspense - key={JSON.stringify(searchParams)} // URL 파라미터가 변경될 때마다 강제 리렌더링 fallback={ <DataTableSkeleton columnCount={8} diff --git a/app/[lng]/evcp/(evcp)/evaluation-check-list/page.tsx b/app/[lng]/evcp/(evcp)/evaluation-check-list/page.tsx index 398005fa..a660c492 100644 --- a/app/[lng]/evcp/(evcp)/evaluation-check-list/page.tsx +++ b/app/[lng]/evcp/(evcp)/evaluation-check-list/page.tsx @@ -32,6 +32,24 @@ async function EvaluationCriteriaPage(props: EvaluationCriteriaPageProps) { return (
<Shell className="gap-2">
+ <div className="flex items-center justify-between space-y-2">
+ <div className="flex items-center justify-between space-y-2">
+ <div>
+ <h2 className="text-2xl font-bold tracking-tight">
+ 협력업체 평가기준표
+ </h2>
+ <p className="text-muted-foreground">
+ 협력업체 평가에 사용되는 평가기준표를 관리{" "}
+ {/* <span className="inline-flex items-center whitespace-nowrap">
+ <Ellipsis className="size-3" />
+ <span className="ml-1">버튼</span>
+ </span>
+ 을 통해 담당자 연락처, 입찰 이력, 계약 이력, 패키지 내용 등을 확인 할 수 있습니다. */}
+ </p>
+ </div>
+ </div>
+ </div>
+
<Suspense fallback={<Skeleton className="h-7 w-52" />}>
{/* <DateRangePicker
triggerSize="sm"
diff --git a/app/[lng]/evcp/(evcp)/evaluation-target-list/page.tsx b/app/[lng]/evcp/(evcp)/evaluation-target-list/page.tsx index d60f695a..088ae75b 100644 --- a/app/[lng]/evcp/(evcp)/evaluation-target-list/page.tsx +++ b/app/[lng]/evcp/(evcp)/evaluation-target-list/page.tsx @@ -26,66 +26,7 @@ interface EvaluationTargetsPageProps { searchParams: Promise<SearchParams> } -// 프로세스 안내 팝오버 컴포넌트 -function ProcessGuidePopover() { - return ( - <Popover> - <PopoverTrigger asChild> - <Button variant="ghost" size="icon" className="h-6 w-6"> - <HelpCircle className="h-4 w-4 text-muted-foreground" /> - </Button> - </PopoverTrigger> - <PopoverContent className="w-96" align="start"> - <div className="space-y-3"> - <div className="space-y-1"> - <h4 className="font-medium">평가 대상 확정 프로세스</h4> - <p className="text-sm text-muted-foreground"> - 발주실적을 기반으로 평가 대상을 확정하는 절차입니다. - </p> - </div> - <div className="space-y-3 text-sm"> - <div className="flex gap-3"> - <div className="flex h-6 w-6 items-center justify-center rounded-full bg-blue-100 text-xs font-medium text-blue-600"> - 1 - </div> - <div> - <p className="font-medium">발주실적 기반 자동 추출</p> - <p className="text-muted-foreground">전년도 10월 ~ 해당년도 9월 발주실적에서 업체 목록을 자동으로 생성합니다.</p> - </div> - </div> - <div className="flex gap-3"> - <div className="flex h-6 w-6 items-center justify-center rounded-full bg-blue-100 text-xs font-medium text-blue-600"> - 2 - </div> - <div> - <p className="font-medium">담당자 지정</p> - <p className="text-muted-foreground">각 평가 대상별로 5개 부서(발주/조달/품질/설계/CS)의 담당자를 지정합니다.</p> - </div> - </div> - <div className="flex gap-3"> - <div className="flex h-6 w-6 items-center justify-center rounded-full bg-blue-100 text-xs font-medium text-blue-600"> - 3 - </div> - <div> - <p className="font-medium">검토 및 의견 수렴</p> - <p className="text-muted-foreground">모든 담당자가 평가 대상 적합성을 검토하고 의견을 제출합니다.</p> - </div> - </div> - <div className="flex gap-3"> - <div className="flex h-6 w-6 items-center justify-center rounded-full bg-blue-100 text-xs font-medium text-blue-600"> - 4 - </div> - <div> - <p className="font-medium">최종 확정</p> - <p className="text-muted-foreground">모든 담당자 의견이 일치하면 평가 대상으로 최종 확정됩니다.</p> - </div> - </div> - </div> - </div> - </PopoverContent> - </Popover> - ) -} + export default async function EvaluationTargetsPage(props: EvaluationTargetsPageProps) { const searchParams = await props.searchParams @@ -131,7 +72,7 @@ export default async function EvaluationTargetsPage(props: EvaluationTargetsPage <Badge variant="outline" className="text-sm"> {currentEvaluationYear}년도 </Badge> - <ProcessGuidePopover /> + </div> </div> </div> @@ -162,10 +103,12 @@ export default async function EvaluationTargetsPage(props: EvaluationTargetsPage /> } > + {currentEvaluationYear && <EvaluationTargetsTable promises={promises} evaluationYear={currentEvaluationYear} /> +} </React.Suspense> </Shell> ) diff --git a/app/[lng]/evcp/(evcp)/evaluation/page.tsx b/app/[lng]/evcp/(evcp)/evaluation/page.tsx index 3ae3272a..ead61077 100644 --- a/app/[lng]/evcp/(evcp)/evaluation/page.tsx +++ b/app/[lng]/evcp/(evcp)/evaluation/page.tsx @@ -17,6 +17,8 @@ import { import { Button } from "@/components/ui/button" import { Badge } from "@/components/ui/badge" import { PeriodicEvaluationsTable } from "@/lib/evaluation/table/evaluation-table" +import { getPeriodicEvaluations } from "@/lib/evaluation/service" +import { searchParamsEvaluationsCache } from "@/lib/evaluation/validation" export const metadata: Metadata = { title: "협력업체 정기평가", @@ -93,25 +95,11 @@ function getDefaultEvaluationYear() { return new Date().getFullYear() } -function searchParamsPeriodicEvaluationsCache() { - // TODO: 실제 파서 구현 - return { - parse: (params: any) => params - } -} -async function getPeriodicEvaluations(params: any) { - // TODO: 실제 API 호출 구현 - return { - data: [], - total: 0, - pageCount: 0 - } -} export default async function PeriodicEvaluationsPage(props: PeriodicEvaluationsPageProps) { const searchParams = await props.searchParams - const search = searchParamsPeriodicEvaluationsCache().parse(searchParams) + const search = searchParamsEvaluationsCache.parse(searchParams) const validFilters = getValidFilters(search.filters || []) // 기본 필터 처리 @@ -150,7 +138,6 @@ export default async function PeriodicEvaluationsPage(props: PeriodicEvaluations <Badge variant="outline" className="text-sm"> {currentEvaluationYear}년도 </Badge> - <ProcessGuidePopover /> </div> </div> </div> diff --git a/app/[lng]/evcp/(evcp)/system/layout.tsx b/app/[lng]/evcp/(evcp)/system/layout.tsx index 62f3e845..7e8f69d0 100644 --- a/app/[lng]/evcp/(evcp)/system/layout.tsx +++ b/app/[lng]/evcp/(evcp)/system/layout.tsx @@ -28,7 +28,7 @@ export default async function SettingsLayout({ const sidebarNavItems = [ { - title: "SHI Users", + title: "삼성중공업 사용자", href: `/${lng}/evcp/system`, }, { @@ -36,13 +36,18 @@ export default async function SettingsLayout({ href: `/${lng}/evcp/system/roles`, }, { - title: "Permissions", + title: "권한 통제", href: `/${lng}/evcp/system/permissions`, }, { - title: "Vendor Users", + title: "협력업체 사용자", href: `/${lng}/evcp/system/admin-users`, }, + + { + title: "비밀번호 정책", + href: `/${lng}/evcp/system/password-policy`, + }, ] diff --git a/app/[lng]/evcp/(evcp)/system/password-policy/page.tsx b/app/[lng]/evcp/(evcp)/system/password-policy/page.tsx new file mode 100644 index 00000000..0f14fefe --- /dev/null +++ b/app/[lng]/evcp/(evcp)/system/password-policy/page.tsx @@ -0,0 +1,63 @@ +// app/admin/password-policy/page.tsx + +import * as React from "react" +import { Skeleton } from "@/components/ui/skeleton" +import { DataTableSkeleton } from "@/components/data-table/data-table-skeleton" +import { Separator } from "@/components/ui/separator" +import { Alert, AlertDescription } from "@/components/ui/alert" +import { AlertTriangle } from "lucide-react" +import SecuritySettingsTable from "@/components/system/passwordPolicy" +import { getSecuritySettings } from "@/lib/password-policy/service" + + +export default async function PasswordPolicyPage() { + try { + // 보안 설정 데이터 로드 + const securitySettings = await getSecuritySettings() + + return ( + <React.Suspense + fallback={ + <DataTableSkeleton + columnCount={4} + searchableColumnCount={0} + filterableColumnCount={0} + cellWidths={["20rem", "30rem", "15rem", "10rem"]} + shrinkZero + /> + } + > + <div className="space-y-6"> + <div> + <h3 className="text-lg font-medium">협력업체 사용자 비밀번호 정책 설정</h3> + <p className="text-sm text-muted-foreground"> + 협력업체 사용자들을 위한 비밀번호 정책과 보안 설정을 관리할 수 있습니다. + </p> + </div> + <Separator /> + <SecuritySettingsTable initialSettings={securitySettings} /> + </div> + </React.Suspense> + ) + } catch (error) { + console.error('Failed to load security settings:', error) + + return ( + <div className="space-y-6"> + <div> + <h3 className="text-lg font-medium">협력업체 사용자 비밀번호 정책 설정</h3> + <p className="text-sm text-muted-foreground"> + 협력업체 사용자들을 위한 비밀번호 정책과 보안 설정을 관리할 수 있습니다. + </p> + </div> + <Separator /> + <Alert variant="destructive"> + <AlertTriangle className="h-4 w-4" /> + <AlertDescription> + 보안 설정을 불러오는 중 오류가 발생했습니다. 페이지를 새로고침하거나 관리자에게 문의하세요. + </AlertDescription> + </Alert> + </div> + ) + } +}
\ No newline at end of file |
